package com.easy.framework.security.service;


import com.easy.framework.common.constant.Constants;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.stereotype.Component;

import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
@Component
public class RedisOAuth2AuthorizationService implements OAuth2AuthorizationService {

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisOAuth2AuthorizationService(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(connectionFactory);
        template.afterPropertiesSet();
        this.redisTemplate = template;
    }

    @Override
    public void save(OAuth2Authorization authorization) {
        // 保存授权信息
        redisTemplate.opsForValue().set(
                Constants.AUTHORIZATION_KEY + authorization.getId(),
                authorization
        );

        // 保存access token索引
        OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
        if (accessToken != null) {
            redisTemplate.opsForValue().set(
                    Constants.ACCESS_TOKEN_KEY + accessToken.getToken().getTokenValue(),
                    authorization.getId()
            );
//            System.out.println(JSON.toJSONString(accessToken.getClaims()));
//            Temporal issuedAt= accessToken.getClaims().get("iat");
//            Temporal expiresAt= accessToken.getClaims().get("exp");
//            long between = ChronoUnit.MINUTES.between(issuedAt, expiresAt);
//            redisTemplate.opsForValue().set(
//                    ACCESS_TOKEN_KEY + accessToken.getToken().getTokenValue(),
//                    authorization.getId(),
//                    between,
//                    TimeUnit.SECONDS
//            );
        }
        // 保存refresh token索引
        OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
        if (refreshToken != null) {
            redisTemplate.opsForValue().set(
                    Constants.REFRESH_TOKEN_KEY + refreshToken.getTokenValue(),
                    authorization.getId()
            );
            long between = ChronoUnit.SECONDS.between(refreshToken.getIssuedAt(), refreshToken.getExpiresAt());
            redisTemplate.opsForValue().set(
                    Constants.REFRESH_TOKEN_KEY + refreshToken.getTokenValue(),
                    authorization.getId(),
                    between,
                    TimeUnit.SECONDS
            );
        }
    }

    @Override
    public void remove(OAuth2Authorization authorization) {
        String id = authorization.getId();

        // 删除access token索引
        OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
        if (accessToken != null) {
            redisTemplate.delete(Constants.ACCESS_TOKEN_KEY + accessToken.getToken().getTokenValue());
        }

        // 删除refresh token索引
        OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
        if (refreshToken != null) {
            redisTemplate.delete(Constants.REFRESH_TOKEN_KEY + refreshToken.getTokenValue());
        }

        // 删除授权信息
        redisTemplate.delete(Constants.AUTHORIZATION_KEY + id);
    }

    @Override
    public OAuth2Authorization findById(String id) {
        return (OAuth2Authorization) redisTemplate.opsForValue().get(Constants.AUTHORIZATION_KEY + id);
    }

    @Override
    public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) {
        if (tokenType == OAuth2TokenType.ACCESS_TOKEN) {
            String id = (String) redisTemplate.opsForValue().get(Constants.ACCESS_TOKEN_KEY + token);
            return id != null ? findById(id) : null;
        } else if (tokenType == OAuth2TokenType.REFRESH_TOKEN) {
            String id = (String) redisTemplate.opsForValue().get(Constants.REFRESH_TOKEN_KEY + token);
            return id != null ? findById(id) : null;
        }
        return null;
    }
}